/**
 * 
 */
package com.firebird.oms.service.sm.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.firebird.base.domain.Page;
import com.firebird.oms.constants.AuthConstants;
import com.firebird.oms.dao.sm.TismFunctionDao;
import com.firebird.oms.dao.sm.TismLoginLogDao;
import com.firebird.oms.dao.sm.TismMenuDao;
import com.firebird.oms.dao.sm.TismRoleDao;
import com.firebird.oms.dao.sm.TismStaffDao;
import com.firebird.oms.dao.sm.TismWorkerChgPwdDao;
import com.firebird.oms.dao.sm.TismWorkerDao;
import com.firebird.oms.domain.sm.TismFunction;
import com.firebird.oms.domain.sm.TismLoginLog;
import com.firebird.oms.domain.sm.TismMenu;
import com.firebird.oms.domain.sm.TismRole;
import com.firebird.oms.domain.sm.TismStaff;
import com.firebird.oms.domain.sm.TismWorker;
import com.firebird.oms.domain.sm.TismWorkerChgPwd;
import com.firebird.oms.exception.OmsRuntimeException;
import com.firebird.oms.service.sm.AuthService;
import com.firebird.oms.user.UserDetails;

/**
 * @author qiuxj
 * @date 2009-11-21
 *
 */
public class AuthServiceImpl implements AuthService {
	
	private static final Log logger = LogFactory.getLog(AuthServiceImpl.class);
	
	private TismMenuDao smMenuDao;
	private TismStaffDao smStaffDao;
	private TismWorkerDao smWorkerDao;
	private TismFunctionDao smFunctionDao;
	private TismRoleDao smRoleDao;
	private TismLoginLogDao smLoginLogDao;
	private TismWorkerChgPwdDao smWorkerChgPwdDao;
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#createFunction(com.firebird.oms.domain.TismFunction)
	 */
	public Serializable createFunction(TismFunction smFunction) {
		return smFunctionDao.create(smFunction);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#updateWorker(com.firebird.oms.domain.TismWorker)
	 */
	public void updateWorker(TismWorker tismWorker) {
		smWorkerDao.update(tismWorker);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#getUniqueWorker(java.lang.String)
	 */
	public TismWorker getUniqueWorker(String loginCode) {
		return smWorkerDao.getUniqueBy("loginCode", loginCode);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#getWorker(int)
	 */
	public TismWorker getWorker(int loginId) {
		return smWorkerDao.get(loginId);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#saveWorker(com.firebird.oms.domain.TismWorker)
	 */
	public void saveWorker(TismWorker tismWorker) {
		smWorkerDao.save(tismWorker);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#getStaff(int)
	 */
	public TismStaff getStaff(int staffId) {
		return smStaffDao.get(staffId);
	}
	
	/**
	 * 获取员工信息列表
	 * @param filter
	 * @return
	 */
	public List<TismStaff> findStaff(Map<String, String> filter) {
		return smStaffDao.find(filter);
	}
	
	/**
	 * 获取员工所有的下级员工
	 * @param upStaffId
	 * @return
	 */
	public List<Integer> getChildStaff(Integer upStaffId) {
		Map<String, String> filter = new HashMap<String, String>();
		filter.put("upperStaffId", upStaffId.toString());
		List<TismStaff> staffs = this.findStaff(filter);
		List<Integer> staffIds = new ArrayList<Integer>();
		staffIds.add(upStaffId);
		for(TismStaff staff : staffs){
			staffIds.add(staff.getStaffId());
		}
		return staffIds;
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#createMenu(com.firebird.oms.domain.TismMenu)
	 */
	public void createMenu(TismMenu menu) {
		int menuCode = smMenuDao.getMaxMenuCode();
		menu.setMenuCode(menuCode);

		smMenuDao.create(menu);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#createRole(com.firebird.oms.domain.TismRole)
	 */
	public Serializable createRole(TismRole smRole) {
		return smRoleDao.create(smRole);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#findMenu(java.util.Map)
	 */
	public List<TismMenu> findMenu(Map<String, String> filter) {
		return smMenuDao.find(filter);
	}

	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#getMenu(int)
	 */
	public TismMenu getMenu(int menuCode) {
		return smMenuDao.get(menuCode);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#getMenuSorted(int)
	 */
	@SuppressWarnings("unchecked")
	public List<TismMenu> getMenuSorted(int menuCode) {
		String hql = "from TismMenu where menuUpCode = ? and menuFlag = 1 order by sortId, menuCode";
		return smMenuDao.find(hql, new Object[]{menuCode});
	}

	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#getTismRole(int)
	 */
	public TismRole getTismRole(int roleId) {
		return smRoleDao.get(roleId);
	}
	
	/**
	 * 获取角色对应的权限
	 * @param roleId
	 * @return
	 */
	public TismRole getTismRoleAndExt(int roleId) {
		TismRole role = this.getTismRole(roleId);
		if (role != null) {
			role.getFunctions().size();
		}

		return role;
	}

	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#getTismFunction(int)
	 */
	public TismFunction getTismFunction(int funcId) {
		return smFunctionDao.get(funcId);
	}
	
	/**
	 * 取得权限及对应的菜单
	 * @param funcId
	 * @return
	 */
	public TismFunction getTismFunctionAndExt(int funcId) {
		TismFunction function = this.getTismFunction(funcId);
		if (function != null) {
			function.getMenus().size();
		}

		return function;
	}

	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#findTismFunctions(java.util.Map)
	 */
	public List<TismFunction> findTismFunctions(Map<String, String> filter) {
		return smFunctionDao.find(filter);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#pageFunction(java.util.Map, java.util.Map, java.util.Map, int, int)
	 */
	public Page pageFunction(Map<String, String> filter, Map<String, String> likeMap, Map<String, String> sortMap,
			int pageNo, int pageSize) {
		return smFunctionDao.pagedQuery(filter, likeMap, sortMap, pageNo, pageSize);
	}

	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#pageRole(java.util.Map, java.util.Map, int, int)
	 */
	public Page pageRole(Map<String, String> filter, Map<String, String> like, int pageNo, int pageSize) {
		return smRoleDao.pagedQuery(filter, like, null, pageNo, pageSize);
	}

	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#findRole(java.util.Map)
	 */
	public List<TismRole> findRole(Map<String, String> filter) {
		return smRoleDao.find(filter);
	}

	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#pageTismMenu(java.util.Map, int, int)
	 */
	public Page pageTismMenu(Map<String, String> filter, int pageNo, int pageSize) {
		return smMenuDao.pagedQuery(filter, null, null, pageNo, pageSize);
	}

	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#updateFunction(com.firebird.oms.domain.TismFunction)
	 */
	public void updateFunction(TismFunction smFunction) {
		smFunctionDao.update(smFunction);
	}

	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#updateMenu(com.firebird.oms.domain.TismMenu)
	 */
	public void updateMenu(TismMenu menu) {
		smMenuDao.update(menu);
	}

	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#updateRole(com.firebird.oms.domain.TismRole)
	 */
	public void updateRole(TismRole smRole) {
		smRoleDao.update(smRole);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#createLoginLog(com.firebird.oms.domain.TismLoginLog)
	 */
	public void createLoginLog(TismLoginLog tismLoginLog){
		smLoginLogDao.create(tismLoginLog);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#getLoginLog(java.util.Map)
	 */
	public List<TismLoginLog> getLoginLog(Map<String, Object> filter){
		return smLoginLogDao.find(filter);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#updateLoginLog(com.firebird.oms.domain.TismLoginLog)
	 */
	public void updateLoginLog(TismLoginLog tismLoginLog) {
		smLoginLogDao.update(tismLoginLog);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#updateAllLoginLog(int, int)
	 */
	public void updateAllLoginLog(int loginId, int logType) {
		Map<String, Object> filter = new HashMap<String, Object>();
		filter.put("loginId", loginId);
		filter.put("logType", logType);
		filter.put("state", AuthConstants.STATE_VALID);
		List<TismLoginLog> loginLogs = this.getLoginLog(filter);
		for(TismLoginLog tismLoginLog : loginLogs){
			tismLoginLog.setState(AuthConstants.STATE_INVALID);
			this.updateLoginLog(tismLoginLog);
		}
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#findWorkerChgPwd(int)
	 */
	@SuppressWarnings("unchecked")
	public List<TismWorkerChgPwd> findWorkerChgPwd(int loginId) {
		String hql = "from TismWorkerChgPwd where loginId = ? order by chgPwdTime desc";
		return smWorkerChgPwdDao.find(hql, new Object[]{loginId});		
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#createWorkerChgPwd(com.firebird.oms.domain.TismWorkerChgPwd)
	 */
	public void createWorkerChgPwd(TismWorkerChgPwd smWorkerChgPwd) {
		smWorkerChgPwdDao.create(smWorkerChgPwd);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#doAuth(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
	 */
	public Map<String, Object> doAuth(String loginCode, String passWord, String sessionId, String ipAddress,String macAddr) {
		Map<String, Object> map = new HashMap<String, Object>();
		TismWorker worker = this.getUniqueWorker(loginCode);

		if (worker == null) {
			map.put(AuthConstants.LOGIN_MESSAGE, "工号不存在");
			
		} else if (!passWord.equals(worker.getLoginPwd())) {
			Map<String, Object> logMap = new HashMap<String, Object>();
			logMap.put("loginId", worker.getLoginId());
			logMap.put("logType", AuthConstants.LOGIN_ERROR_LOG);
			logMap.put("state", AuthConstants.STATE_VALID);
			List<TismLoginLog> loginLogs = this.getLoginLog(logMap);
			
			if (loginLogs.size() < AuthConstants.LONIN_ERROR_MAX - 1) {
				TismLoginLog log = new TismLoginLog();
				log.setLoginId(worker.getLoginId());
				log.setSessionId(sessionId);
				log.setIpAddr(ipAddress);
				log.setMacAddr(macAddr);
				log.setLogType(AuthConstants.LOGIN_ERROR_LOG);//登录失败日志
				log.setErrDesc("登录密码错误");
				log.setLogTime(new Date());
				log.setState(AuthConstants.STATE_VALID);
				this.createLoginLog(log);
				logger.info("登录密码错误：loginCode = " + loginCode);
				
				map.put(AuthConstants.LOGIN_MESSAGE, "登录密码错误");
			} else {
				worker.setState(AuthConstants.WORKER_STATE_LOCK);
				this.saveWorker(worker);
				logger.info("工号已锁定：loginCode = " + loginCode);
				
				map.put(AuthConstants.LOGIN_MESSAGE, "工号已锁定");
			}
		} else {
			switch (worker.getState()) {
			case AuthConstants.WORKER_STATE_INVALID: // 失效
				map.put(AuthConstants.LOGIN_MESSAGE, "工号已失效");
				break;
			case AuthConstants.WORKER_STATE_LOCK: // 锁定
				map.put(AuthConstants.LOGIN_MESSAGE, "工号已锁定");
				break;
			case AuthConstants.WORKER_STATE_VALID: // 可用

				if (AuthConstants.WORKER_LEVEL_ADMIN != worker.getLoginLevel()) { // 判断密码是否过期 , ADMIN类型不判断
					Long days = (new Date().getTime() - worker.getLastChgPwdTime().getTime()) / (1000 * 60 * 60 * 24);

					if (days >= 90) {
						worker.setState(AuthConstants.WORKER_STATE_LOCK);
						this.updateWorker(worker);
						
						map.put(AuthConstants.LOGIN_MESSAGE, "密码已过期,工号锁定");
						return map;
					}

				}

				TismStaff staff = this.getStaff(worker.getStaffId());

				// 清除错误登录记录
				this.updateAllLoginLog(worker.getLoginId(), AuthConstants.LOGIN_ERROR_LOG);
				
				worker.setLoginNum(worker.getLoginNum() + 1);
				this.saveWorker(worker);
				
				map.put(AuthConstants.LOGIN_ID, worker.getLoginId());
				map.put(AuthConstants.LOGIN_USERNAME, staff.getStaffName());
				map.put(AuthConstants.LOGIN_NUM, worker.getLoginNum());
				map.put(AuthConstants.LOGIN_LEVEL, worker.getLoginLevel());
				map.put(AuthConstants.STAFF_ID, worker.getStaffId());
				map.put(AuthConstants.UP_STAFF_ID, staff.getUpperStaffId());

				// 查找密码最后修改时间
				List<TismWorkerChgPwd> ls = this.findWorkerChgPwd(worker.getLoginId());
				
				if (ls.size() > 0) {
					map.put(AuthConstants.PASSWD_LAST_CHGDATE, ls.get(0).getChgPwdTime());
				} else {
					map.put(AuthConstants.PASSWD_LAST_CHGDATE, new Date());
				}
				break;
			default:
				throw new OmsRuntimeException("不支持的工号状态");
			}
		}

		return map;
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#doLogout(int, java.lang.String, java.lang.String, java.lang.String)
	 */
	public void doLogout(int loginId, String sessionId, String ipAddress, String macAddr) {
		TismLoginLog log = new TismLoginLog();
		log.setLoginId(loginId);
		log.setSessionId(sessionId);
		log.setIpAddr(ipAddress);
		log.setMacAddr(macAddr);
		log.setLogType(AuthConstants.LOGIN_OUT_LOG);//退出日志
		log.setLogTime(new Date());
		log.setState(AuthConstants.STATE_VALID);
		this.createLoginLog(log);
		logger.info("用户退出，退出时间为：" + new Date());
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#doChangePassword(int, java.lang.String)
	 */
	public void doChangePassword(int loginId, String password) {
		TismWorker worker = this.getWorker(loginId);
		
		TismWorkerChgPwd smWorkerChgPwd = new TismWorkerChgPwd();
		smWorkerChgPwd.setBeforePwd(worker.getLoginPwd());
		smWorkerChgPwd.setChgPwdTime(new Date());
		smWorkerChgPwd.setAfterPwd(password);
		smWorkerChgPwd.setLoginId(loginId);
		this.createWorkerChgPwd(smWorkerChgPwd);

		worker.setLastChgPwdTime(new Date());
		worker.setLoginPwd(password);

		this.updateWorker(worker);
	}
	
	/* (non-Javadoc)
	 * @see com.firebird.oms.service.sm.impl.AuthService#findMenus(com.firebird.oms.user.UserDetails, int)
	 */
	public List<TismMenu> findMenus(UserDetails currentUser, int menuCode) {
		// 获取当前菜单有效的子菜单
		List<TismMenu> ls = this.getMenuSorted(menuCode);

		if (currentUser.getLoginlevel() > AuthConstants.WORKER_LEVEL_SYSTEM) {
			List<TismMenu> authMenus = this.getUserMenu(currentUser.getLogincode());

			for (Iterator<TismMenu> it = ls.iterator(); it.hasNext();) {
				TismMenu menu = it.next();
				if (!authMenus.contains(menu)) {
					it.remove();
				}
			}
		}

		return ls;
	}
	
	/**
	 * 获取当前用户的菜单
	 * @param loginCode
	 * @return
	 */
	private List<TismMenu> getUserMenu(String loginCode) {
		List<TismMenu> ls = new ArrayList<TismMenu>();
		TismWorker worker = this.getUniqueWorker(loginCode);

		Set<TismFunction> funcs = new HashSet<TismFunction>(worker.getFunctions());
		
		for (TismRole role : worker.getRoles()) {
			funcs.addAll(role.getFunctions());
		}

		for (TismFunction func : funcs) {
			ls.addAll(func.getMenus());
		}

		return ls;
	}
	
	/**
	 * 判断用户输入的密码是否在最近5次的密码修改记录 如果是，则不能修改密码（返回false）
	 * @param loginId
	 * @param password
	 * @return
	 */
	public Boolean isPwdChg(int loginId, String password) {
		List<TismWorkerChgPwd> chgPwds = this.findWorkerChgPwd(loginId);
		
		int i = 1;
		for(TismWorkerChgPwd chgPwd : chgPwds){
			if(i == 5){
				break;
			}
			if(chgPwd.getAfterPwd().equals(password)){
				return false;
			}
		}
		return true;
	}

	public void setSmMenuDao(TismMenuDao smMenuDao) {
		this.smMenuDao = smMenuDao;
	}

	public void setSmStaffDao(TismStaffDao smStaffDao) {
		this.smStaffDao = smStaffDao;
	}

	public void setSmWorkerDao(TismWorkerDao smWorkerDao) {
		this.smWorkerDao = smWorkerDao;
	}

	public void setSmFunctionDao(TismFunctionDao smFunctionDao) {
		this.smFunctionDao = smFunctionDao;
	}

	public void setSmRoleDao(TismRoleDao smRoleDao) {
		this.smRoleDao = smRoleDao;
	}

	public void setSmLoginLogDao(TismLoginLogDao smLoginLogDao) {
		this.smLoginLogDao = smLoginLogDao;
	}

	public void setSmWorkerChgPwdDao(TismWorkerChgPwdDao smWorkerChgPwdDao) {
		this.smWorkerChgPwdDao = smWorkerChgPwdDao;
	}

	

}
